export {};
/*
方法装饰器
  用来监视、修改或则替换方法定义
  方法装饰器会在调用时时传入下列3个参数:
    1. 对于静态成员来说是类的构造函数，对于实例成员来说是类的原型对象
    2. 成员的名称
    3. 成员的属性描述符 // 如果代码输出目标小于 ES5，属性描述符会是 undefined。

注意：
  方法装饰器不能用在声明文件( .d.ts)，重载或者任何外部上下文（比如declare的类）中。
*/


/** 1. 通过方法装饰器给类原型添加属性*/
/*function logMethod(params:any){
  return function(target:any,methodsName:any,desc:any){
    console.log('target:', target); //target: {getData: ƒ, constructor: ƒ}
    console.log('methodsName:', methodsName); //methodsName: getData
    console.log('desc:', desc); //desc: {value: ƒ, writable: true, enumerable: true, configurable: true}

    target.apiUrl = 'xxx';
    target.run = function(){
      console.log('run');
    }
  }
}

class HttpClient{
  public url: any | undefined;

  constructor(){

  }

  @logMethod('x')
  getData(){
    console.log('this.url:',this.url)
  }
}


const http:any = new HttpClient();
console.log(http.apiUrl)
http.run();*/







/** 2. 切面编程*/
function logMethod(params:any){
  return function(target:any,methodsName:any,desc:any){
    console.log('target:', target); //target: {getData: ƒ, constructor: ƒ}
    console.log('methodsName:', methodsName); //methodsName: getData
    console.log('desc:', desc); //desc: {value: ƒ, writable: true, enumerable: true, configurable: true}

    //修改装饰器的方法 把装饰器方法里面传入的所有参数改为string类型

    //1、 保存当前的方法
    const oldMethod = desc.value;
    //2、 替换原方法
    desc.value = function(...args:any[]){
      args = args.map((value) => {
        return String(value);
      });

      console.log('args:',args);
      oldMethod.apply(this,args);
    }
  }
}

class HttpClient{
  public url: any | undefined;

  constructor(){

  }

  @logMethod('x')
  getData(...args:any[]){
    console.log('我在原本的getData里打印')
  }
}


const http = new HttpClient();
http.getData(123,'xxx')



/** 3. 如果方法装饰器返回一个值，那么会用这个值作为方法的属性描述符对象：*/
//我们在这个例子中，在方法装饰器中返回一个对象，对象中包含 value 用来修改方法，enumerable 用来设置可枚举性。我们可以看到最后打印出的 info.getAge()的结果为"not age"，说明我们成功使用function () { return “not age” }替换了被装饰的方法getAge () { return this.age }

//注意，当构建目标小于 ES5 的时候，方法装饰器的返回值会被忽略
function enumerable(bool: boolean): any {
  return function(
    target: any,
    propertyName: string,
    descriptor: PropertyDescriptor
  ) {
    return {
      value: function() {
        return "not age";
      },
      enumerable: bool
    };
  };
}
class Info {
  constructor(public age: number) {}
  @enumerable(false)
  getAge() {
    return this.age;
  }
}
const info = new Info(1);
console.log(info.getAge()); // "not age"
